const cluster = require('cluster');
const commander = require('commander');
const {exec, execSync} = require('child_process')
const fs = require('fs');
const path = require('path')
const chalk = require('chalk')
const copy = require('copy-concurrently')
const rm = require('rimraf')
const numCPUs = require('os').cpus().length;
const packageJSON = require('./package.json');

const SITES_PATH = path.join(__dirname, 'sites')
const SITES_CONFIG_PATH = path.join(__dirname, 'build', 'sites')
const SITES_TEMPLATE_PATH = path.join(__dirname, 'build', 'templates')
const PACKAGE_PATH = path.join(__dirname, 'package.json')


function build(apps, isPreview) {
  if (cluster.isMaster) {
    let arr = apps
    let result = [];
    let startTime = new Date().getTime()
    console.log(`正在运行代码生成器...`)
    let ret = execSync('npm run coder')
    if (ret) {
      console.log(chalk.green(`生成代码完成！`))
    } else {
      console.log(chalk.red(`生成代码失！`))
    }
    
    process.on('exit', function () {
      console.log('全部网站发布完成，用时：' + ((new Date().getTime() - startTime) / 1000) + ' s')
      console.log(chalk.green(`--------------------------------`))
    })
    arr.forEach(function (item, i) {
      let index = i % numCPUs;
      let sub = result[index];
      if (!sub) {
        result[index] = []
      }
      result[index].push(item)
    })
    
    for (let i = 0; i < numCPUs; i++) {
      cluster.fork();
    }
    
    Object.keys(cluster.workers).forEach(function (id) {
      cluster.workers[id].on('message', function (msg) {
        if (msg.type === 'start') {
          cluster.workers[msg.id].send(result[msg.id - 1] || [])
        }
        if (msg.type === 'success') {
        
        }
        if (msg.type === 'finish') {
          cluster.workers[msg.id].disconnect()
        }
        
      })
    })
    
  } else {
    process.on('message', function (sites) {
      queue(sites, function (name) {
        return new Promise((resolve, reject) => {
          console.log(`${name}正在发布......`)
          exec(`npm run build_${name} ${isPreview ? '--preview' : ''}`, function (err) {
            if (err) {
              console.log(chalk.red(`${name} 发布失败！`))
              console.log(err)
              reject(err)
              return
            }
            console.log(chalk.green(`${name} 发布成功！`))
            process.send({typ: 'success', name: name});
            resolve()
          })
          
        })
      }, function () {
        process.send({type: 'finish', id: cluster.worker.id, sites: sites});
      })
      
    });
    process.send({type: 'start', id: cluster.worker.id});
  }
}

function queue(array, func, finish) {
  if (array.length > 0) {
    let item = array.shift()
    func(item).then(() => {
      queue(array, func, finish)
    }).catch(e => {
      queue(array, func, finish)
    })
  } else {
    finish && finish()
  }
}

function replaceConfig(path, name, port) {
  let content = fs.readFileSync(path, 'utf-8')
  content = content.replace(/{{name}}/g, name).replace(/{{port}}/g, port);
  fs.writeFileSync(path, content, 'utf-8')
}

function addPackageCmd(name) {
  const dev = 'npm run coder && ' +
    'node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development ' +
    'node node_modules/webpack-dev-server/bin/webpack-dev-server.js ' +
    '--mode development --hot --inline --progress ' +
    '--config build/sites/' + name + '/dev.js';
  const build = 'node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production ' +
    'node build/sites/' + name + '/build.js';
  
  packageJSON.scripts[`dev_${name}`] = dev;
  packageJSON.scripts[`build_${name}`] = build;
  fs.writeFileSync(PACKAGE_PATH, JSON.stringify(packageJSON, null, 2), 'utf-8')
}


commander.version(packageJSON.version)
  .option('-a, --add <name>', '新增网站')
  .option('-p, --port <name>', '网站端口')
  .option('-r, --remove <name>', '删除网站')
  .option('-b, --build', '发布所有网站')
  .option('-pv, --preview', '发布成功后预览网站')
  .parse(process.argv);

if (commander.add) {
  const sitePath = path.join(SITES_PATH, commander.add)
  if (fs.existsSync(sitePath)) {
    console.log(chalk.yellow(`${commander.add} 目录名称已存在，请更换名称`))
    return;
  }
  const fromSitePath = path.join(SITES_TEMPLATE_PATH, 'app')
  const formConfigPath = path.join(SITES_TEMPLATE_PATH, 'config')
  const toConfigPath = path.join(SITES_CONFIG_PATH, commander.add)
  const copySite = copy(fromSitePath, sitePath)
  const copyConfig = copy(formConfigPath, toConfigPath)
  Promise.all([copySite, copyConfig])
    .then(() => {
      const configFile = path.join(toConfigPath, 'config.js')
      replaceConfig(configFile, commander.add, commander.port || 8001)
      addPackageCmd(commander.add)
      console.log(chalk.green(`${commander.add} 创建成功`))
    })
    .catch(e => {
      console.log(chalk.red(`${commander.add} 创建失败`))
      console.log(e)
    })
}

if (commander.remove) {
  const sitePath = path.join(SITES_PATH, commander.remove)
  if (!fs.existsSync(sitePath)) {
    console.log(chalk.yellow(`${commander.remove} 目录名称不存在`))
    return;
  }
  const toConfigPath = path.join(SITES_CONFIG_PATH, commander.remove)
  rm.sync(sitePath)
  rm.sync(toConfigPath)
  delete packageJSON.scripts[`dev_${commander.remove}`]
  delete packageJSON.scripts[`build_${commander.remove}`]
  fs.writeFileSync(PACKAGE_PATH, JSON.stringify(packageJSON, null, 2), 'utf-8')
  console.log(chalk.green(`${commander.remove} 删除成功！`))
}

if (commander.build) {
  const apps = fs.readdirSync(SITES_PATH).filter(dir => !dir.includes('.'))
  build(apps, commander.preview)
}


